package org.opengauss.driver;

import org.opengauss.Logger;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * author: z00588921
 * date: 2020/9/14
 * descript:
 */
public class DriverInfoManager {
    public static final String PROP_FILE_NAME = "database.properties";
    public static final String PROP_ALL_KEY = "all_keys";
    public static final String PROP_ACTIVITY = "activity_key";
    private Map<String, IDriverInfo> infos = new HashMap<>();

    public static final DriverInfoManager instance = new DriverInfoManager();
    public static final String OG_DRIVER = "org.opengauss.Driver";
    public static final String MYSQL_DRIVER = "com.mysql.jdbc.Driver";

    private String activityKey = "db";
    private DriverInfoManager() {
        Properties prop = loadProperties();
        List<String> keys = Arrays.stream(prop.getProperty(PROP_ALL_KEY).split(","))
                .filter(a -> !"".equals(a))
                .map(a -> a.trim())
                .collect(Collectors.toList());
        for (String key : keys) {
            Properties jdbcProp = parseJdbcProperties(key, prop);
            Properties urlProp = parseUrlProperties(key, prop);
            IDriverInfo info = createDriverInfo(jdbcProp, urlProp);
            this.infos.put(key, info);
        }
        activityKey = prop.getProperty(PROP_ACTIVITY);
    }

    public String getActivity() {
        return activityKey;
    }

    public static IDriverInfo getInfo(String key) {
        return instance.infos.get(key);
    }

    public static IDriverInfo getInfo() {
        return instance.infos.get(instance.getActivity());
    }

    public static void registerDriver() {
        registerDriver(OG_DRIVER);
        registerDriver(MYSQL_DRIVER);
    }

    public static boolean registerDriver(String driverName) {
        try {
            Class.forName(driverName);
            return true;
        } catch (ClassNotFoundException e) {
            Logger.info("register driver failed!" + e.toString());
        }
        return false;
    }

    public static Connection getConnection(IDriverInfo info) throws SQLException {
        return DriverManager.getConnection(info.getFormatConnectionInfo(),
                info.getProperties());
    }

    private static Properties localUserProperties() {
        String filePath = System.getProperty("user.dir")
            + File.separator
            + PROP_FILE_NAME;
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream(filePath));
            return properties;
        }catch (Exception exception){
            Logger.info("file to load config from: "+ filePath + " err=" + exception.getMessage());
            return null;
        }
    }
    public static Properties loadProperties() {
        Properties useProp = localUserProperties();
        if (useProp != null) {
            return useProp;
        }

        Properties prop = new Properties();
        try (InputStream is = DriverInfoManager.class.getClassLoader().getResourceAsStream(PROP_FILE_NAME)) {
            prop.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return prop;
    }

    public static Properties parseJdbcProperties(String key, Properties prop) {
        return parseConnectorProperties(key, "jdbc", prop);
    }

    public static Properties parseUrlProperties(String key, Properties prop) {
        return parseConnectorProperties(key, "url", prop);
    }

    public static Properties parseConnectorProperties(String key, String connector, Properties prop) {
        Properties tmpProp = new Properties();
        String prefix = key + "." + connector + ".";
        Enumeration<?> names = prop.propertyNames();
        while (names.hasMoreElements()) {
            String name = names.nextElement().toString();
            if (name.startsWith(prefix)) {
                tmpProp.put(name.substring(prefix.length()), prop.getProperty(name));
            }
        }
        return tmpProp;
    }

    public static IDriverInfo createDriverInfo(Properties jdbcProp, Properties urlProp) {
        String type = jdbcProp.remove("type").toString();
        if (type.equals("opengauss")) {
            return new OpenGaussDriverInfo(jdbcProp, urlProp);
        } else if (type.equals("mysql")) {
            return new MysqlDriverInfo(jdbcProp, urlProp);
        } else {
            return null;
        }
    }
}
